import os
import requests
from datetime import datetime, timedelta
from xml.etree import ElementTree as ET
from xml.dom import minidom
import configparser
import re
import json


class TMDBUtils:
    """TMDB工具类，提供影视信息获取、搜索及NFO文件生成功能，支持简化的代理配置"""

    def __init__(self, api_key, proxy_ip=None, proxy_port=None, proxy=None):
        """初始化工具类

        Args:
            api_key: TMDB API密钥
            proxy_ip: 代理IP地址
            proxy_port: 代理端口号
            proxy: 为了保持向后兼容性保留的旧代理配置参数
        """
        self.api_key = api_key
        self.base_url = "https://api.themoviedb.org/3"
        self.image_base_url = "https://image.tmdb.org/t/p/"
        self.headers = {"Accept": "application/json"}
        
        # 优先使用拆分后的proxy_ip和proxy_port参数
        if proxy_ip and proxy_port:
            self.proxy = self._format_proxy(f"{proxy_ip}:{proxy_port}")
        elif proxy:
            # 为了向后兼容性，如果没有提供拆分的参数但提供了旧的proxy参数，则使用旧参数
            self.proxy = self._format_proxy(proxy)
        else:
            self.proxy = None
        
        self.country_code_map = self._get_country_codes()
        
    def check_connection(self):
        """检查TMDB API连接状态"""
        try:
            if not self.api_key:
                return False, "未配置API密钥"
            
            # 使用_make_request方法来测试连接
            response_data = self._make_request("configuration")
            
            if response_data and 'images' in response_data:
                return True, "连接成功"
            else:
                return False, "连接失败"
                
        except Exception as e:
            return False, str(e)

    def _format_proxy(self, proxy):
        """将IP+端口格式转换为requests所需的代理字典格式"""
        if not proxy:
            return None

        # 如果是字符串，尝试解析为IP+端口格式
        if isinstance(proxy, str):
            # 移除可能的协议前缀
            proxy = proxy.replace("http://", "").replace("https://", "")
            # 分割IP和端口
            if ":" in proxy:
                ip, port = proxy.split(":", 1)
                return {
                    'http': f'http://{ip}:{port}',
                    'https': f'http://{ip}:{port}'
                }
            else:
                print(f"代理格式错误：{proxy}，请使用IP:端口格式（如127.0.0.1:7890）")
                return None

        # 如果是字典，直接使用
        elif isinstance(proxy, dict):
            return proxy

        # 其他类型
        else:
            print("代理格式错误，应使用字符串（IP:端口）或字典")
            return None

    def _get_country_codes(self):
        """获取国家代码与名称的映射表"""
        countries = self._make_request("configuration/countries") or []
        return {country['iso_3166_1']: country['english_name'] for country in countries}

    def _make_request(self, endpoint, params=None):
        """发送API请求的内部方法，支持代理"""
        if not params:
            params = {}
        params["api_key"] = self.api_key

        url = f"{self.base_url}/{endpoint}"

        try:
            response = requests.get(
                url,
                headers=self.headers,
                params=params,
                proxies=self.proxy,
                timeout=10
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"API请求失败: {e}")
            # 尝试自动切换备用域名
            if "api.themoviedb.org" in url:
                print("尝试使用备用域名访问...")
                self.base_url = "https://api.tmdb.org/3"
                return self._make_request(endpoint, params)
            return None

    # 搜索功能 - 支持ID和名称搜索
    def search_media(self, query, media_type=None, page=1, language="zh-CN"):
        """搜索影视资源，支持按名称搜索"""
        try:
            results = []

            if media_type == "movie":
                response = self._make_request(
                    "search/movie",
                    params={"query": query, "page": page, "language": language}
                )
                if response and "results" in response:
                    results = [{
                        "type": "movie",
                        "id": item["id"],
                        "title": item["title"],
                        "original_title": item["original_title"],
                        "release_date": item.get("release_date"),
                        "overview": item.get("overview"),
                        "poster_url": f"{self.image_base_url}w500{item['poster_path']}" if item.get(
                            "poster_path") else None,
                        "vote_average": item.get("vote_average")
                    } for item in response["results"]]

            elif media_type == "tv":
                response = self._make_request(
                    "search/tv",
                    params={"query": query, "page": page, "language": language}
                )
                if response and "results" in response:
                    results = [{
                        "type": "tv",
                        "id": item["id"],
                        "name": item["name"],
                        "original_name": item["original_name"],
                        "first_air_date": item.get("first_air_date"),
                        "overview": item.get("overview"),
                        "poster_url": f"{self.image_base_url}w500{item['poster_path']}" if item.get(
                            "poster_path") else None,
                        "vote_average": item.get("vote_average")
                    } for item in response["results"]]

            else:
                movie_response = self._make_request(
                    "search/movie",
                    params={"query": query, "page": page, "language": language}
                )
                if movie_response and "results" in movie_response:
                    results.extend([{
                        "type": "movie",
                        "id": item["id"],
                        "title": item["title"],
                        "release_date": item.get("release_date"),
                        "poster_url": f"{self.image_base_url}w500{item['poster_path']}" if item.get("poster_path") else None
                    } for item in movie_response["results"]])

                tv_response = self._make_request(
                    "search/tv",
                    params={"query": query, "page": page, "language": language}
                )
                if tv_response and "results" in tv_response:
                    results.extend([{
                        "type": "tv",
                        "id": item["id"],
                        "name": item["name"],
                        "first_air_date": item.get("first_air_date"),
                        "poster_url": f"{self.image_base_url}w500{item['poster_path']}" if item.get("poster_path") else None
                    } for item in tv_response["results"]])

            return True, results
        except Exception as e:
            print(f"搜索媒体失败: {str(e)}")
            return False, str(e)

    def get_media_by_id(self, media_id, media_type):
        """通过ID获取影视资源详情"""
        if not media_type or media_type not in ["movie", "tv"]:
            print("请指定有效的媒体类型: 'movie' 或 'tv'")
            return None

        if media_type == "movie":
            return self.get_movie_nfo_info(media_id)
        else:
            return self.get_tv_nfo_info(media_id)
            
    def get_media_detail(self, media_id, media_type):
        """获取媒体详情，返回(状态, 结果)格式"""
        try:
            result = self.get_media_by_id(media_id, media_type)
            if result:
                return True, result
            else:
                return False, "未找到媒体信息"
        except Exception as e:
            print(f"获取媒体详情失败: {str(e)}")
            return False, str(e)

    # 24小时内影视列表功能
    def get_recent_movies_24h(self, page=1, language="zh-CN"):
        """获取24小时内更新的电影列表（含标题和海报）"""
        try:
            yesterday = datetime.now() - timedelta(days=1)
            yesterday_str = yesterday.strftime("%Y-%m-%d")

            results = self._make_request(
                "discover/movie",
                params={
                    "page": page,
                    "language": language,
                    "primary_release_date.gte": yesterday_str,
                    "sort_by": "primary_release_date.desc"
                }
            )

            if not results or "results" not in results:
                return True, []

            movie_list = [
                {
                    "id": item["id"],
                    "title": item["title"],
                    "poster_url": f"{self.image_base_url}w500{item['poster_path']}" if item.get("poster_path") else None,
                    "release_date": item.get("release_date"),
                    "vote_average": item.get("vote_average")
                }
                for item in results["results"]
            ]
            
            return True, movie_list
        except Exception as e:
            print(f"获取最新电影失败: {str(e)}")
            return False, str(e)

    def get_recent_tv_24h(self, page=1, language="zh-CN"):
        """获取24小时内更新的电视节目列表（含标题和海报）"""
        try:
            yesterday = datetime.now() - timedelta(days=1)
            yesterday_str = yesterday.strftime("%Y-%m-%d")

            results = self._make_request(
                "discover/tv",
                params={
                    "page": page,
                    "language": language,
                    "first_air_date.gte": yesterday_str,
                    "sort_by": "first_air_date.desc"
                }
            )

            if not results or "results" not in results:
                return True, []

            tv_list = [
                {
                    "id": item["id"],
                    "name": item["name"],
                    "poster_url": f"{self.image_base_url}w500{item['poster_path']}" if item.get("poster_path") else None,
                    "first_air_date": item.get("first_air_date"),
                    "vote_average": item.get("vote_average")
                }
                for item in results["results"]
            ]
            
            return True, tv_list
        except Exception as e:
            print(f"获取最新电视节目失败: {str(e)}")
            return False, str(e)

    # 电影NFO信息获取
    def get_movie_nfo_info(self, movie_id, language="zh-CN"):
        """获取电影的NFO信息"""
        details = self._make_request(
            f"movie/{movie_id}",
            params={
                "language": language,
                "append_to_response": "credits,release_dates,external_ids"
            }
        )

        if not details:
            return None

        poster_url = f"{self.image_base_url}w500{details.get('poster_path')}" if details.get('poster_path') else None
        backdrop_url = f"{self.image_base_url}w1280{details.get('backdrop_path')}" if details.get(
            'backdrop_path') else None

        directors = [p['name'] for p in details.get('credits', {}).get('crew', []) if p['job'] == 'Director']
        writers = [p['name'] for p in details.get('credits', {}).get('crew', []) if
                   p['job'] in ['Writer', 'Screenplay', 'Story']]
        actors = [
            {'name': p['name'], 'character': p.get('character', '未知角色'), 'order': p.get('order', 0)}
            for p in details.get('credits', {}).get('cast', [])[:15]
        ]

        countries = [c['name'] for c in details.get('production_countries', [])]
        companies = [c['name'] for c in details.get('production_companies', [])]

        certification = ""
        for release in details.get('release_dates', {}).get('results', []):
            if release['iso_3166_1'] == 'US' and release['release_dates']:
                certification = release['release_dates'][0].get('certification', '')
                break

        return {
            "type": "movie",
            "id": details.get('id'),
            "title": details.get('title'),
            "original_title": details.get('original_title'),
            "overview": details.get('overview'),
            "tagline": details.get('tagline'),
            "genres": [g['name'] for g in details.get('genres', [])],
            "directors": directors,
            "writers": writers,
            "actors": actors,
            "release_date": details.get('release_date'),
            "runtime": details.get('runtime'),
            "countries": countries,
            "production_companies": companies,
            "language": details.get('original_language'),
            "vote_average": details.get('vote_average'),
            "vote_count": details.get('vote_count'),
            "popularity": details.get('popularity'),
            "certification": certification,
            "poster_url": poster_url,
            "backdrop_url": backdrop_url,
            "imdb_id": details.get('external_ids', {}).get('imdb_id'),
            "tmdb_id": details.get('id'),
            "status": details.get('status')
        }

    # 电视节目NFO信息获取
    def get_tv_nfo_info(self, tv_id, language="zh-CN"):
        """获取电视节目的NFO信息"""
        details = self._make_request(
            f"tv/{tv_id}",
            params={
                "language": language,
                "append_to_response": "credits,external_ids,content_ratings"
            }
        )

        if not details:
            return None

        poster_url = f"{self.image_base_url}w500{details.get('poster_path')}" if details.get('poster_path') else None
        backdrop_url = f"{self.image_base_url}w1280{details.get('backdrop_path')}" if details.get(
            'backdrop_path') else None

        creators = [p['name'] for p in details.get('created_by', [])]
        actors = [
            {'name': p['name'], 'character': p.get('character', '未知角色'), 'order': p.get('order', 0)}
            for p in details.get('credits', {}).get('cast', [])[:15]
        ]
        writers = [p['name'] for p in details.get('credits', {}).get('crew', []) if p['job'] == 'Writer']

        countries = []
        for code in details.get('origin_country', []):
            countries.append(self.country_code_map.get(code, code))

        certification = ""
        for rating in details.get('content_ratings', {}).get('results', []):
            if rating['iso_3166_1'] == 'US':
                certification = rating.get('rating', '')
                break

        return {
            "type": "tv",
            "id": details.get('id'),
            "name": details.get('name'),
            "original_name": details.get('original_name'),
            "overview": details.get('overview'),
            "tagline": details.get('tagline'),
            "genres": [g['name'] for g in details.get('genres', [])],
            "creators": creators,
            "writers": writers,
            "actors": actors,
            "first_air_date": details.get('first_air_date'),
            "last_air_date": details.get('last_air_date'),
            "number_of_seasons": details.get('number_of_seasons'),
            "number_of_episodes": details.get('number_of_episodes'),
            "countries": countries,
            "language": details.get('original_language'),
            "vote_average": details.get('vote_average'),
            "vote_count": details.get('vote_count'),
            "popularity": details.get('popularity'),
            "certification": certification,
            "poster_url": poster_url,
            "backdrop_url": backdrop_url,
            "imdb_id": details.get('external_ids', {}).get('imdb_id'),
            "tmdb_id": details.get('id'),
            "status": details.get('status'),
            "episode_run_time": details.get('episode_run_time')
        }

    # NFO文件生成功能
    def generate_nfo_file(self, media_info, media_type=None):
        """生成NFO文件，与app.py中的调用匹配"""
        if not media_info:
            print("没有有效的媒体信息，无法生成NFO文件")
            return None

        # 优先从环境变量获取NFO保存目录
        output_dir = os.environ.get('TMDB_NFO_DIR')
        
        # 如果环境变量未设置，从配置文件读取
        if not output_dir:
            current_dir = os.path.dirname(os.path.abspath(__file__))
            parent_dir = os.path.dirname(current_dir)
            config_path = os.path.join(parent_dir, 'config', 'config.json')
            
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    output_dir = config['app'].get('nfo_dir', './data/nfo_files')
            except Exception as e:
                print(f"加载配置文件失败: {str(e)}")
                output_dir = './data/nfo_files'

        media_type = media_info["type"]

        if not os.path.exists(output_dir):
            os.makedirs(output_dir)

        if media_type == "movie":
            root = ET.Element("movie")
            title = media_info["title"]
            filename = f"{title}.nfo".replace("/", "-")
        else:
            root = ET.Element("tvshow")
            title = media_info["name"]
            filename = f"{title}.nfo".replace("/", "-")

        self._add_element(root, "title", title)
        self._add_element(root, "originaltitle", media_info.get("original_title") or media_info.get("original_name"))
        self._add_element(root, "overview", media_info.get("overview"))
        self._add_element(root, "tagline", media_info.get("tagline"))
        self._add_element(root, "rating", media_info.get("vote_average"))
        self._add_element(root, "votes", media_info.get("vote_count"))
        self._add_element(root, "popularity", media_info.get("popularity"))
        self._add_element(root, "mpaa", media_info.get("certification"))
        self._add_element(root, "language", media_info.get("language"))
        self._add_element(root, "status", media_info.get("status"))

        self._add_element(root, "tmdbid", media_info.get("tmdb_id"))
        self._add_element(root, "imdbid", media_info.get("imdb_id"))

        if media_type == "movie":
            self._add_element(root, "releasedate", media_info.get("release_date"))
            self._add_element(root, "runtime", media_info.get("runtime"))
        else:
            self._add_element(root, "premiered", media_info.get("first_air_date"))
            self._add_element(root, "lastaired", media_info.get("last_air_date"))
            self._add_element(root, "season", media_info.get("number_of_seasons"))
            self._add_element(root, "episode", media_info.get("number_of_episodes"))
            self._add_element(root, "runtime", media_info.get("episode_run_time"))

        for country in media_info.get("countries", []):
            self._add_element(root, "country", country)

        for genre in media_info.get("genres", []):
            self._add_element(root, "genre", genre)

        for company in media_info.get("production_companies", []):
            self._add_element(root, "studio", company)

        if media_type == "movie":
            for director in media_info.get("directors", []):
                self._add_element(root, "director", director)
        else:
            for creator in media_info.get("creators", []):
                self._add_element(root, "creator", creator)

        for writer in media_info.get("writers", []):
            self._add_element(root, "writer", writer)

        for actor in media_info.get("actors", []):
            actor_elem = ET.SubElement(root, "actor")
            self._add_element(actor_elem, "name", actor["name"])
            self._add_element(actor_elem, "role", actor["character"])
            self._add_element(actor_elem, "order", actor["order"])

        self._add_element(root, "thumb", media_info.get("poster_url"))
        self._add_element(root, "fanart", media_info.get("backdrop_url"))

        rough_string = ET.tostring(root, 'utf-8')
        reparsed = minidom.parseString(rough_string)
        pretty_xml = reparsed.toprettyxml(indent="  ")

        file_path = os.path.join(output_dir, filename)
        try:
            with open(file_path, "w", encoding="utf-8") as f:
                lines = pretty_xml.split('\n')
                clean_lines = [line for line in lines if line.strip() != '']
                f.write('\n'.join(clean_lines))
            print(f"NFO文件已生成: {file_path}")
            return file_path
        except IOError as e:
            print(f"保存NFO文件失败: {e}")
            return None

    def _add_element(self, parent, tag, value):
        """辅助方法：添加XML元素"""
        if value is not None:
            elem = ET.SubElement(parent, tag)
            if isinstance(value, list):
                elem.text = ", ".join(map(str, value))
            else:
                elem.text = str(value)
                
    def download_poster(self, poster_url, title, media_id):
        """下载海报图片到配置的图片目录"""
        try:
            # 获取配置中的图片保存目录
            current_dir = os.path.dirname(os.path.abspath(__file__))
            parent_dir = os.path.dirname(current_dir)
            config_path = os.path.join(parent_dir, 'config', 'config.json')
            
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    image_dir = config['app'].get('image_dir', './data/images')
            except Exception as e:
                print(f"加载配置文件失败: {str(e)}")
                image_dir = './data/images'
            
            # 确保目录存在
            os.makedirs(image_dir, exist_ok=True)
            
            # 生成安全的文件名
            safe_title = re.sub(r'[\\/:*?"<>|]', '', title)
            filename = f"{safe_title}_{media_id}.jpg"
            filepath = os.path.join(image_dir, filename)
            
            # 下载海报
            response = requests.get(poster_url, proxies=self.proxy, timeout=10)
            response.raise_for_status()
            
            # 保存海报
            with open(filepath, 'wb') as f:
                f.write(response.content)
            
            print(f"海报已下载: {filepath}")
            return filepath
        except Exception as e:
            print(f"下载海报失败: {str(e)}")
            return None
    